package net.citrite.android;


import com.android.sdklib.AndroidVersion;
import com.android.sdklib.SdkVersionInfo;
import com.android.xml.AndroidManifest;
import org.python.antlr.ast.Str;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

import static com.android.SdkConstants.ANDROID_NS_NAME;
import static com.android.xml.AndroidManifest.*;

public class ManifestParser {
    private AndroidVersion minSdkVersion = AndroidVersion.DEFAULT;
    private AndroidVersion targetSdkVersion = AndroidVersion.DEFAULT;
    private String packageName;
    private String appTheme = "theme";
    private Map<String, String> activityMap = new HashMap<String, String>();
    private File manifestFile;

    public ManifestParser(File manifestFile) throws XPathExpressionException {
        this.manifestFile = manifestFile;
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setNamespaceAware(true);
        Document doc = null;
        try {
            DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
            doc = builder.parse(manifestFile);
        } catch (Exception e) {
            throw new IllegalArgumentException("AndroidManifest.xml is invalid");
        }
        XPath xpath = XPathBuilder.newXPath();
        String finder = String.format("/%s/%s/@%s:%s", NODE_MANIFEST, NODE_USES_SDK, ANDROID_NS_NAME, ATTRIBUTE_MIN_SDK_VERSION);
        String version = xpath.evaluate(finder, doc);
        if (!version.isEmpty()) {
            minSdkVersion = SdkVersionInfo.getVersion(version, null);
        } else {
            minSdkVersion = AndroidVersion.DEFAULT;
        }

        // target sdk version
        finder = String.format("/%s/%s/@%s:%s", NODE_MANIFEST, NODE_USES_SDK, ANDROID_NS_NAME, ATTRIBUTE_TARGET_SDK_VERSION);
        version = xpath.evaluate(finder, doc);
        if (!version.isEmpty()) {
            targetSdkVersion = SdkVersionInfo.getVersion(version, null);
        } else {
            targetSdkVersion = AndroidVersion.DEFAULT;
        }

        // package name
        finder = String.format("/%s/@%s", NODE_MANIFEST, ATTRIBUTE_PACKAGE);
        packageName = xpath.evaluate(finder, doc);
        if (packageName.isEmpty()) {
            throw new IllegalArgumentException("No package attribute in AndroidManifest.xml");
        }
        finder = String.format("/%s/%s", NODE_MANIFEST, NODE_APPLICATION);
        Node application = (Node)xpath.evaluate(finder, doc, XPathConstants.NODE);
        if (application != null) {
            finder = String.format("@%s:%s", ANDROID_NS_NAME, ATTRIBUTE_THEME);
            appTheme = xpath.evaluate(finder, application);
            finder = NODE_ACTIVITY;
            NodeList activities = (NodeList)xpath.evaluate(finder, application, XPathConstants.NODESET);
            if (activities != null) {
                for (int index = 0; index < activities.getLength(); index ++) {
                    Node activity = activities.item(index);
                    finder = String.format("@%s:%s", ANDROID_NS_NAME, ATTRIBUTE_NAME);
                    String name = xpath.evaluate(finder, activity);
                    finder = String.format("@%s:%s", ANDROID_NS_NAME, ATTRIBUTE_THEME);
                    String theme = xpath.evaluate(finder, activity);
                    if (theme.isEmpty()) {
                        theme = appTheme;
                    }
                    name = AndroidManifest.combinePackageAndClassName(packageName, name);
                    activityMap.put(name, theme);
                }
            }
        }
    }

    public File getManifestFile() {
        return manifestFile;
    }

    public String getPackageName() {
        return packageName;
    }

    public String getAppTheme() {
        return appTheme;
    }

    public String getActivityTheme(String name) {
        if (name == null || name.isEmpty()) {
            return appTheme;
        }
        String fullName = AndroidManifest.combinePackageAndClassName(packageName, name);
        if (activityMap.containsKey(fullName)) {
            return activityMap.get(fullName);
        }
        return appTheme;
    }
}
